package com.example.fw;

import static org.testng.Assert.assertEquals;

import java.util.List;
import java.util.Random;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;
import com.example.tests.ContactData;
import com.example.utils.SortedListOf;

public class ContactHelper extends WebDriverHelperBase {
	
	public static boolean CREATION = true;
	public static boolean MODIFICATION = false;

	public ContactHelper(ApplicationManager manager) {
		super(manager);
	}

	public ContactHelper createContact(ContactData contact) {
		manager.navigateTo().mainPage();
		initContactCreation();
		fillContactForm(contact, CREATION, OVERWRITE);
		submitContactCreation();
		returnToHomePage();
		manager.getModelContacts().addContact(contact);
		return this;
	}

	public ContactHelper modifyContact(int index, ContactData contact, boolean mode) {
		manager.navigateTo().mainPage();
		initContactModification(index);
		fillContactForm(contact, MODIFICATION, mode);
		submitContactModification();
		returnToHomePage();
		if (mode == KEEP) {
		 	// update oldGroup with non-empty fields of group
	    ContactData oldContact = manager.getModelContacts().getContacts().get(index);
	    oldContact.updateContact(contact, MODIFICATION);
			manager.getModelContacts().removeContact(index).addContact(oldContact);
		} else {
			manager.getModelContacts().removeContact(index).addContact(contact);
		}
		return this;
	}

	public ContactHelper deleteContact(int index) {
		manager.navigateTo().mainPage();
		initContactModification(index);
		submitContactRemoval();
		returnToHomePage();
		manager.getModelContacts().removeContact(index);
		return this;
	}

	public void verifyContactDetails(ContactData contact, int index) {
		manager.navigateTo().mainPage();
 		// get contact details
		openContactDetails(index);
		
 		// check contact details match contact data
		assertEquals(compareWithContactDetails(contact), true);
 		
		// print contact details
		openContactPrintPage();
		
		// verify printed details match contact data
		assertEquals(compareWithContactPrintDetails(contact), true);
		manager.navigateTo().reopenMainPage();
	}

// --------------------------Low level methods separator
	
//	private void rebuildCachedContactsOld() {
//		cachedContacts = new SortedListOf<ContactData>();
//		
//		manager.navigateTo().mainPage();
//		List<WebElement> checkboxes = driver.findElements(By.name("selected[]"));
//		for (WebElement checkbox : checkboxes) {
//
//			// get first and last name of contact
//			String text = checkbox.getAttribute("title");
//			text = text.substring("Select (".length(), text.length() - ")".length());
//			ContactData contact = new ContactData()
//					.withFirstName(text.substring(0, text.indexOf(' ')))
//					.withLastName(text.substring(text.indexOf(' ') + 1));
//			
//			text = checkbox.getAttribute("accept");
//			if (text.indexOf(';') != -1) {
//				// contact has 2 email addresses
//				contact.withFirstEmailAddress(text.substring(0, text.indexOf(';')))
//						.withSecondEmailAddress(text.substring(text.indexOf(';')+1));
//			} else {
//				// contact has one or empty email address
//				contact.withFirstEmailAddress(text);
//			}
//			
//			// app sorts by last name, then by first name, phone nr, email address
//			cachedContacts.add(contact);
//		}
//	}
//	
	public SortedListOf<ContactData> getUiContacts() {
		SortedListOf<ContactData> uiContacts = new SortedListOf<ContactData>();
		
		manager.navigateTo().mainPage();
    WebElement table_element = driver.findElement(By.id("maintable"));
    List<WebElement> contactsList=table_element.findElements(By.xpath("id('maintable')/tbody/tr[@name='entry']"));
    for(WebElement contactRow : contactsList) {
			ContactData contact = new ContactData()
				.withFirstName(contactRow.findElement(By.xpath("td[2]")).getText())
				.withLastName(contactRow.findElement(By.xpath("td[3]")).getText())
				.withFirstEmailAddress(contactRow.findElement(By.xpath("td[4]")).getText()) //may be in fact second email address
				.withHomePhoneNr(contactRow.findElement(By.xpath("td[5]")).getText()); //may be in fact mobile or work phone
			uiContacts.add(contact);
    }
    return uiContacts;
	}

	public ContactHelper initContactCreation() {
		click(By.linkText("add new"));
		return this;
	}

	public ContactHelper fillContactForm(ContactData contact, boolean formType, boolean mode) {
		type(By.name("firstname"), contact.getFirstName(), mode);
		type(By.name("lastname"), contact.getLastName(), mode);
		type(By.name("address"), contact.getPrimaryAddress(), mode);
		type(By.name("home"), contact.getHomePhoneNr(), mode);
		type(By.name("mobile"), contact.getMobilePhoneNr(), mode);
		type(By.name("work"), contact.getWorkPhoneNr(), mode);
		type(By.name("email"), contact.getFirstEmailAddress(), mode);
		type(By.name("email2"), contact.getSecondEmailAddress(), mode);
		selectByText(By.name("bday"), contact.getBirthdayDay());
		selectByText(By.name("bmonth"), contact.getBirthdayMonth());
    type(By.name("byear"), contact.getBirthdayYear(), mode);
    if (formType == CREATION) {
//	    	selectByText(By.name("new_group"), contact.getContactGroup());
		} else {
			if (driver.findElements(By.name("new_group")).size() !=0) {
				throw new Error("Group selector exists in contact modification form");
			}
	}
    type(By.name("address2"), contact.getSecondaryAddress(), mode);
		type(By.name("phone2"), contact.getSecondaryHomePhoneNr(), mode);
		return this;
	}

	public ContactHelper submitContactCreation() {
		click(By.name("submit"));
		return this;
	}

	public ContactHelper returnToHomePage() {
		click(By.linkText("home page"));
		return this;
	}

	public ContactHelper submitContactModification() {
		click(By.xpath("//input[@type='submit'][@value='Update']"));
		return this;
	}

	public ContactHelper initContactModification(int index) {
		clickImage(By.xpath("//tr["+ (index + 2) +"]/td[7]/a/img"));
		return this;
	}

	public ContactHelper submitContactRemoval() {
		click(By.xpath("//input[@type='submit'][@value='Delete']"));
		return this;
	}

	// returns random index if list is not empty, otherwise returns -1
	public int getRandomContactIndex(SortedListOf<ContactData> contactList) {
		int index = 0;
		if (contactList.size() > 1) {
			Random rnd = new Random();
			index = rnd.nextInt(contactList.size()-1);
    } else if (contactList.size() == 0) {
			index = -1;
		}
		return index;
	}

	public ContactHelper openContactDetails(int index) {
		clickImage(By.xpath("//tr["+ (index + 2) +"]/td[6]/a/img"));
		return this;
	}

	public ContactHelper openContactPrintPage() {
		click(By.xpath("//input[@type='submit'][@value='Print']"));
		return this;
	}

	public boolean compareWithContactDetails(ContactData contact) {
		String contactDetails = driver.findElement(By.id("content")).getText();
		return contactMatchesDetails(contact, contactDetails);
	}

	public boolean compareWithContactPrintDetails(ContactData contact) {
		String contactDetails = driver.findElement(By.xpath("//*[@id=\"container\"]/div[1]")).getText();
		return contactMatchesDetails(contact, contactDetails);
	}

	private boolean contactMatchesDetails(ContactData contact, String contactDetails) {
		String[] contactDetailsRows = contactDetails.split("\n");
		boolean phoneFound = false;
		boolean mailFound=false;
		Pattern pattern = Pattern.compile("\\(w{3}\\.(\\S)*\\)"); 
		
		for (int i = 0; i < contactDetailsRows.length; i++) {
			String contactLine = contactDetailsRows[i].trim();
			if (i == 0) {
				if (!contactLine.substring(0, contactLine.length() - 1).trim().equals((contact.getFirstName() + " " + contact.getLastName()).trim())) return false;
			}
			
			if (contactLine.trim().startsWith("H: ")) {
				if (!contactLine.substring("H: ".length()).equals(contact.getHomePhoneNr().trim())) {
					return false;
				} else {
					phoneFound = true;
				}
			}

			if ((!phoneFound) && contactLine.trim().startsWith("M: ")) {
				if (!contactLine.substring("M: ".length()).equals(contact.getHomePhoneNr().trim())) {
					return false;
				} else {
					phoneFound = true;
				}
			}

			if ((!phoneFound) && contactLine.trim().startsWith("W: ")) {
				if (!contactLine.substring("W: ".length()).equals(contact.getHomePhoneNr().trim())) {
					return false;
				} else {
					phoneFound = true;
				}
			}

			Matcher matcher = pattern.matcher(contactLine.trim());
			if ((!mailFound) && matcher.find())
			{
				String mail = contactLine.trim().substring(0, matcher.start()-1); 
		    if (!mail.equals(contact.getFirstEmailAddress())) {
		    	return false;
		    } else {
		    	mailFound = true;
		    }
			}
		}
		
		return true;
	}

}
